package com.blog.blog.common;

import cn.hutool.core.exceptions.ExceptionUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import java.util.List;
import java.util.stream.Collectors;

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})
    public ResponseEntity<ApiBaseResponse<ApiErrorResponse>> handleBodyValidation(Exception ex, HttpServletRequest request) {
        List<String> errors;
        if (ex instanceof MethodArgumentNotValidException manv) {
            errors = manv.getBindingResult()
                    .getFieldErrors()
                    .stream()
                    .map(err -> err.getField() + ": " + err.getDefaultMessage())
                    .collect(Collectors.toList());
        } else if (ex instanceof BindException be) {
            errors = be.getBindingResult()
                    .getFieldErrors()
                    .stream()
                    .map(err -> err.getField() + ": " + err.getDefaultMessage())
                    .collect(Collectors.toList());
        } else {
            errors = List.of("参数校验失败");
        }
        return buildError(HttpStatus.BAD_REQUEST, request, "参数校验失败", errors);
    }

    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<ApiBaseResponse<ApiErrorResponse>> handleConstraintViolation(ConstraintViolationException ex, HttpServletRequest request) {
        List<String> errors = ex.getConstraintViolations().stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.toList());
        return buildError(HttpStatus.BAD_REQUEST, request, "参数校验失败", errors);
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<ApiBaseResponse<ApiErrorResponse>> handleIllegalArgument(IllegalArgumentException ex, HttpServletRequest request) {
        return buildError(HttpStatus.BAD_REQUEST, request, ex.getMessage(), null);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ApiBaseResponse<ApiErrorResponse>> handleOther(Exception ex, HttpServletRequest request) {
        log.error("发生未知异常 : {}", ExceptionUtil.getMessage(ex));
        return buildError(HttpStatus.INTERNAL_SERVER_ERROR, request, "服务器内部错误", List.of(ex.getClass().getSimpleName()));
    }

    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public ResponseEntity<ApiBaseResponse<ApiErrorResponse>> handleMaxUpload(MaxUploadSizeExceededException ex, HttpServletRequest request) {
        return buildError(HttpStatus.PAYLOAD_TOO_LARGE, request, "上传文件过大，请压缩或降低分辨率后重试", null);
    }

    private ResponseEntity<ApiBaseResponse<ApiErrorResponse>> buildError(HttpStatus status, HttpServletRequest request, String message, List<String> details) {
        ApiErrorResponse err = new ApiErrorResponse();
        err.setStatus(status.value());
        err.setError(status.getReasonPhrase());
        err.setMessage(message);
        err.setPath(request.getRequestURI());
        err.setDetails(details);
        ApiBaseResponse<ApiErrorResponse> body = ApiBaseResponse.<ApiErrorResponse>error(status.value(), message).withData(err);
        return new ResponseEntity<>(body, status);
    }
}


